package nucleus.view; import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; import android.os.Bundle; import android.os.Parcelable; import android.widget.FrameLayout; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import mocks.BundleMock; import nucleus.factory.ReflectionPresenterFactory; import nucleus.factory.RequiresPresenter; import nucleus.presenter.Presenter; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.powermock.api.mockito.PowerMockito.when; import static org.powermock.api.support.membermodification.MemberMatcher.constructor; import static org.powermock.api.support.membermodification.MemberMatcher.method; import static org.powermock.api.support.membermodification.MemberModifier.stub; import static org.powermock.api.support.membermodification.MemberModifier.suppress; @RunWith(PowerMockRunner.class) @PrepareForTest({NucleusLayoutTest.TestView.class, PresenterLifecycleDelegate.class, ReflectionPresenterFactory.class}) public class NucleusLayoutTest { public static final Class<?> BASE_VIEW_CLASS = FrameLayout.class; public static final Class<TestView> VIEW_CLASS = TestView.class; public static class TestPresenter extends Presenter { } @RequiresPresenter(TestPresenter.class) public static class TestView extends NucleusLayout { public TestView() { super(null); } @Override public boolean isInEditMode() { return false; } } public void setUpIsFinishing(boolean b) { Activity activity = mock(Activity.class); when(activity.isFinishing()).thenReturn(b); when(activity.isChangingConfigurations()).thenReturn(!b); stub(method(BASE_VIEW_CLASS, "getContext")).toReturn(activity); } private TestPresenter mockPresenter; private PresenterLifecycleDelegate mockDelegate; private ReflectionPresenterFactory mockFactory; private TestView tested; private void setUpPresenter() throws Exception { mockPresenter = mock(TestPresenter.class); PowerMockito.whenNew(Bundle.class).withNoArguments().thenAnswer(new Answer<Bundle>() { @Override public Bundle answer(InvocationOnMock invocation) throws Throwable { return BundleMock.mock(); } }); mockDelegate = mock(PresenterLifecycleDelegate.class); PowerMockito.whenNew(PresenterLifecycleDelegate.class).withAnyArguments().thenReturn(mockDelegate); when(mockDelegate.getPresenter()).thenReturn(mockPresenter); mockFactory = mock(ReflectionPresenterFactory.class); when(mockFactory.createPresenter()).thenReturn(mockPresenter); PowerMockito.mockStatic(ReflectionPresenterFactory.class); when(ReflectionPresenterFactory.fromViewClass(any(Class.class))).thenReturn(mockFactory); } @Before public void setUp() throws Exception { setUpPresenter(); tested = spy(VIEW_CLASS); suppress(constructor(BASE_VIEW_CLASS, Context.class)); suppress(method(BASE_VIEW_CLASS, "onRestoreInstanceState", Parcelable.class)); suppress(method(BASE_VIEW_CLASS, "onSaveInstanceState")); suppress(method(BASE_VIEW_CLASS, "onAttachedToWindow")); suppress(method(BASE_VIEW_CLASS, "onDetachedFromWindow")); setUpIsFinishing(false); } @Test public void testCreation() throws Exception { assertEquals(mockPresenter, tested.getPresenter()); PowerMockito.verifyStatic(times(1)); ReflectionPresenterFactory.fromViewClass(argThat(new ArgumentMatcher<Class<?>>() { @Override public boolean matches(Object argument) { return TestView.class.isAssignableFrom((Class)argument); } })); verify(mockDelegate, times(1)).getPresenter(); verifyNoMoreInteractions(mockPresenter, mockDelegate, mockFactory); } @Test public void testLifecycle() throws Exception { tested.onAttachedToWindow(); verify(mockDelegate, times(1)).onResume(tested); tested.onDetachedFromWindow(); verify(mockDelegate, times(1)).onDropView(); verify(mockDelegate, times(1)).onDestroy(false); tested.onSaveInstanceState(); verify(mockDelegate, times(1)).onSaveInstanceState(); verifyNoMoreInteractions(mockPresenter, mockDelegate, mockFactory); } @Test public void testSaveRestore() throws Exception { Bundle presenterBundle = BundleMock.mock(); when(mockDelegate.onSaveInstanceState()).thenReturn(presenterBundle); Bundle state = (Bundle)tested.onSaveInstanceState(); tested = spy(TestView.class); tested.onRestoreInstanceState(state); verify(mockDelegate).onRestoreInstanceState(presenterBundle); } @Test public void testDestroy() throws Exception { setUpIsFinishing(true); tested.onDetachedFromWindow(); verify(mockDelegate, times(1)).onDestroy(true); } @Test public void getActivityFromContext() throws Exception { Activity activity = mock(Activity.class); stub(method(BASE_VIEW_CLASS, "getContext")).toReturn(activity); assertEquals(activity, tested.getActivity()); } @Test public void getActivityFromWrappedContext() throws Exception { Activity activity = mock(Activity.class); ContextWrapper wrapper = mock(ContextWrapper.class); when(wrapper.getBaseContext()).thenReturn(activity); ContextWrapper wrapper2 = mock(ContextWrapper.class); when(wrapper2.getBaseContext()).thenReturn(wrapper); stub(method(BASE_VIEW_CLASS, "getContext")).toReturn(wrapper2); assertEquals(activity, tested.getActivity()); } }